package com.file.parser;

import com.file.bo.ResponseData;
import com.file.bo.mail.ICBC;
import com.file.bo.mail.ICBCTran;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import com.google.common.base.Splitter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


@Slf4j
public class ICBCPdfParser extends BaseDecryptPdfParser {

    public ResponseData<String> parseICBCPdfToJson(String daId, String filePath, String pdfPassword) {
        log.info("parseICBCPdfToJson started, daId:{}, pdfPassword:{}", daId, pdfPassword);
        String json = null;

        try {
            ICBC icbc = parseICBCPdf(filePath, pdfPassword);
            json = JsonUtils.convertObjectToJson(icbc);
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseICBCPdfToJson failed", e);
            return new ResponseData<String>(json, ErrorCode.FILE_PARSE_EXCEPTION.getCode(),
                    ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseICBCPdfToJson completed, daId:{}, pdfPassword:{}", daId, pdfPassword);
        return new ResponseData<String>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private ICBC parseICBCPdf(String filePath, String pdfPassword) {
        ICBC icbc = parseICBCHeader(filePath, pdfPassword);
        List<ICBCTran> icbcTrans = parseICBCTrans(filePath, pdfPassword);
        icbc.setIcbcTrans(icbcTrans);
        log.info("icbc = " + icbc);
        return icbc;
    }

    private ICBC parseICBCHeader(String filePath, String pdfPassword) {
        ICBC icbc = new ICBC();
        String pdfHeaderText = parsePdfHeaderText(filePath, pdfPassword);
        String cardNo = pdfHeaderText.substring(pdfHeaderText.indexOf("卡号") + 2, pdfHeaderText.indexOf("户名：")).trim();
        String name = pdfHeaderText.substring(pdfHeaderText.indexOf("户名：") + 3, pdfHeaderText.indexOf("起止日期：")).trim();
        String transDetailPeriod = pdfHeaderText
                .substring(pdfHeaderText.indexOf("起止日期：") + 5, pdfHeaderText.indexOf("交易日期")).trim();
        icbc.setCardNo(cardNo);
        icbc.setName(name);
        icbc.setTransDetailPeriod(transDetailPeriod);
        return icbc;
    }

    private List<ICBCTran> parseICBCTrans(String filePath, String pdfPassword) {
        List<ICBCTran> icbcTrans = new ArrayList<>();
        List<String> rowList = new ArrayList<>();
        List<Integer> indexList = new ArrayList<>();

        String text = getPdfTextByStripper(filePath, pdfPassword);
        // 兼容交易日期 换行和空格
        Pattern pattern = Pattern.compile("(\\d{4}-\\d{2}-\\d{2}(\n|(\r\n)|\\s)\\d{2}:\\d{2}:\\d{2})|(交易日期)");//NOSONAR
        Matcher matcher = pattern.matcher(text);
        while (matcher.find()) {
            indexList.add(matcher.start());
        }

        for (int i = 0; i < indexList.size() - 1; i++) {
            String tranRow = text.substring(indexList.get(i), indexList.get(i + 1));
            if (tranRow.contains("本页支出算术合计")) {
                tranRow = tranRow.substring(0, tranRow.indexOf("本页支出算术合计"));
            }
            if (tranRow.contains("页共")) {
                continue;
            }
            rowList.add(tranRow);

        }

        String lastRow = text.substring(indexList.get(indexList.size() - 1));
        if (lastRow.contains("本页支出算术合计")) {
            lastRow = lastRow.substring(0, lastRow.indexOf("本页支出算术合计"));
        }
        if (!lastRow.contains("页共")) {
            rowList.add(lastRow);
        }

        List<String> headers = new ArrayList<>();
        for (int index = 0; index < rowList.size(); index++) {
            String row = rowList.get(index);
            if (row.contains("交易日期")) {
                String separatorLine = System.getProperty("line.separator", "\n");
                headers = Arrays.stream(String.join("", Splitter.on(separatorLine)
                        .splitToList(row)).split(StringUtils.SPACE)).collect(Collectors.toList());

                continue;
            }
            ICBCTran icbcTran = new ICBCTran();
            Pattern pattern1 = Pattern.compile("\\d{4}-\\d{2}-\\d{2}(\n|(\r\n))\\d{2}:\\d{2}:\\d{2}");
            Matcher matcher1 = pattern1.matcher(row);
            if (matcher1.find()) {
                String separatorLine = System.getProperty("line.separator", "\n");
                List<String> list = Splitter.on(separatorLine).splitToList(row);
                StringBuilder stringBuilder = new StringBuilder(list.get(0));
                for (int i = 1; i < list.size(); i++) {
                    stringBuilder.append(list.get(i));
                }
                List<String> cols = Splitter.on(StringUtils.SPACE).splitToList(stringBuilder.toString());
                // 处理cols和headers对应不上用例
                if (cols.size() != headers.size()) {
                    cols = new ArrayList<>(cols);
                    // 适配储种和币种为空的用例
                    if (cols.get(2).matches("\\d{5,}") && (cols.get(5).matches("\\d{4,}"))) {
                        cols.add(2, "");
                        cols.add(4, "");
                    }
                    //  适配对方户名分割多列用例:App Store _ Apple Music
                    int balanceIndex = headers.indexOf("余额");
                    int conterpartyAccountNoIndex = headers.indexOf("对方账号");

                    if ((cols.size() > headers.size()) &&
                            balanceIndex > 0 && conterpartyAccountNoIndex > 0
                            && cols.get(balanceIndex).matches("(([0-9]{1,3}(,[0-9]{3})*)(\\.[0-9]{2}))")) {
                        List<String> conterpartyAccountNames = new ArrayList<>();
                        for (int i = balanceIndex + 1; i <= cols.size() - 3; i++) {
                            conterpartyAccountNames.add(cols.get(i));
                        }
                        if (!conterpartyAccountNames.isEmpty()) {
                            cols.subList(balanceIndex + 1, cols.size() - 3).clear();
                            cols.set(balanceIndex + 1, StringUtils.join(conterpartyAccountNames, " "));
                        }
                    }
                }
                if (cols.size() == 11) {
                    String balance = cols.get(9).trim();
                    if (balance.substring(balance.indexOf(".") + 1).length() > 2) {
                        icbcTran.setTranDate(cols.get(0));
                        icbcTran.setAccountNo(cols.get(1));
                        icbcTran.setAccountType(cols.get(2));
                        icbcTran.setSequenceNo(cols.get(3));
                        icbcTran.setCurrency(cols.get(4));
                        icbcTran.setCashExchange(cols.get(5));
                        icbcTran.setComment(cols.get(6));
                        icbcTran.setZone(cols.get(7));
                        icbcTran.setIncomeExpenseAmt(cols.get(8));
                        parseBalanceAndCounterpartyNameAndCounterpartyAccountNo(cols.get(9), icbcTran);
                        icbcTran.setChannel(cols.get(10));
                        icbcTrans.add(icbcTran);
                    } else {
                        icbcTran.setTranDate(cols.get(0));
                        icbcTran.setAccountNo(cols.get(1));
                        icbcTran.setAccountType(cols.get(2));
                        icbcTran.setSequenceNo(cols.get(3));
                        icbcTran.setCurrency(cols.get(4));
                        icbcTran.setCashExchange(cols.get(5));
                        icbcTran.setComment(cols.get(6));
                        icbcTran.setZone(cols.get(7));
                        icbcTran.setIncomeExpenseAmt(cols.get(8));
                        icbcTran.setBalance(cols.get(9));
                        icbcTran.setChannel(cols.get(10));
                        icbcTrans.add(icbcTran);
                    }
                }
                // 有对方户名 & 对方账号
                else if (cols.size() == 13) {
                    icbcTran.setTranDate(cols.get(0));
                    icbcTran.setAccountNo(cols.get(1));
                    icbcTran.setAccountType(cols.get(2));
                    icbcTran.setSequenceNo(cols.get(3));
                    icbcTran.setCurrency(cols.get(4));
                    icbcTran.setCashExchange(cols.get(5));
                    icbcTran.setComment(cols.get(6));
                    icbcTran.setZone(cols.get(7));
                    icbcTran.setIncomeExpenseAmt(cols.get(8));
                    icbcTran.setBalance(cols.get(9));
                    icbcTran.setCounterpartyName(cols.get(10));
                    icbcTran.setConterpartyAccountNo(cols.get(11));
                    icbcTran.setChannel(cols.get(12));
                    icbcTrans.add(icbcTran);
                } else if (cols.size() == 12) {
                    // 摘要为空
                    if (cols.get(6).matches("[0-9]{4}")) {  //NOSONAR
                        icbcTran.setTranDate(cols.get(0));
                        icbcTran.setAccountNo(cols.get(1));
                        icbcTran.setAccountType(cols.get(2));
                        icbcTran.setSequenceNo(cols.get(3));
                        icbcTran.setCurrency(cols.get(4));
                        icbcTran.setCashExchange(cols.get(5));
                        icbcTran.setComment("");
                        icbcTran.setZone(cols.get(6));
                        icbcTran.setIncomeExpenseAmt(cols.get(7));
                        icbcTran.setBalance(cols.get(8));
                        icbcTran.setCounterpartyName(cols.get(9));
                        icbcTran.setConterpartyAccountNo(cols.get(10));
                        icbcTran.setChannel(cols.get(11));
                        icbcTrans.add(icbcTran);
                        // 对方户名和对方账号连在一起
                    } else if (cols.get(10).matches("[\\u4e00-\\u9fa5]{2,}[A-Za-z0-9_*\\-]{6,35}")) {  //NOSONAR
                        Matcher matcher2 = Pattern.compile("[A-Za-z0-9_*\\-]{6,35}").matcher(cols.get(10));
                        if (matcher2.find()) {
                            icbcTran.setCounterpartyName(cols.get(10).replace(matcher2.group(), ""));
                            icbcTran.setConterpartyAccountNo(matcher2.group());
                        }
                        icbcTran.setTranDate(cols.get(0));
                        icbcTran.setAccountNo(cols.get(1));
                        icbcTran.setAccountType(cols.get(2));
                        icbcTran.setSequenceNo(cols.get(3));
                        icbcTran.setCurrency(cols.get(4));
                        icbcTran.setCashExchange(cols.get(5));
                        icbcTran.setComment(cols.get(6));
                        icbcTran.setZone(cols.get(7));
                        icbcTran.setIncomeExpenseAmt(cols.get(8));
                        icbcTran.setBalance(cols.get(9));
                        icbcTran.setChannel(cols.get(11));
                        icbcTrans.add(icbcTran);
                        // 余额和对方户名连在一起
                    } else if (cols.get(9).matches("[0-9]{1,3}(,[0-9]{3})*(\\.[0-9]{2})?[\\u4e00-\\u9fa5]{2,}.*")) {    //NOSONAR
                        Matcher matcher3 = Pattern.compile("[0-9]{1,3}(,[0-9]{3})*(\\.[0-9]{2})").matcher(cols.get(9));
                        if (matcher3.find()) {
                            icbcTran.setBalance(matcher3.group());
                            icbcTran.setCounterpartyName(cols.get(9).replace(matcher3.group(), ""));
                        }
                        icbcTran.setTranDate(cols.get(0));
                        icbcTran.setAccountNo(cols.get(1));
                        icbcTran.setAccountType(cols.get(2));
                        icbcTran.setSequenceNo(cols.get(3));
                        icbcTran.setCurrency(cols.get(4));
                        icbcTran.setCashExchange(cols.get(5));
                        icbcTran.setComment(cols.get(6));
                        icbcTran.setZone(cols.get(7));
                        icbcTran.setIncomeExpenseAmt(cols.get(8));
                        icbcTran.setConterpartyAccountNo(cols.get(10));
                        icbcTran.setChannel(cols.get(11));
                        icbcTrans.add(icbcTran);
                    } else {
                        System.out.println(StringUtils.join(cols, " "));
                        // 对方账户出现多行的情况，自动和对方户名又连到了一起
                        // 取最后一段数字及其之后的部分作为对方账号，剩余的部分作为对方户名
                        String counterpartyNameAndAccount = cols.get(10);
                        Pattern patternc = Pattern.compile("\\d+");
                        Matcher matcherc = patternc.matcher(counterpartyNameAndAccount);
                        String counterpartyName = StringUtils.EMPTY;
                        String counterpartyAcc = StringUtils.EMPTY;
                        int lastNumberStartIndex = -1;
                        int lastNumberEndIndex = -1;
                        // 遍历所有匹配的数字串，记录最后一个数字的结束位置
                        while (matcherc.find()) {
                            lastNumberStartIndex = matcherc.start();
                            lastNumberEndIndex = matcherc.end();
                        }
                        // 如果找到了数字，返回从最后一个数字开始到最后的子字符串作为账户id
                        if (lastNumberEndIndex != -1) {
                            counterpartyAcc = counterpartyNameAndAccount.substring(lastNumberStartIndex);
                        }
                        // 剩下的部分作为账户名
                        int lastNumberStartIndex2 = counterpartyNameAndAccount.indexOf(counterpartyAcc);
                        if (lastNumberStartIndex2 != -1) {
                            counterpartyName = counterpartyNameAndAccount.substring(0, lastNumberStartIndex2);
                        }
                        icbcTran.setTranDate(cols.get(0));
                        icbcTran.setAccountNo(cols.get(1));
                        icbcTran.setAccountType(cols.get(2));
                        icbcTran.setSequenceNo(cols.get(3));
                        icbcTran.setCurrency(cols.get(4));
                        icbcTran.setCashExchange(cols.get(5));
                        icbcTran.setComment(cols.get(6));
                        icbcTran.setZone(cols.get(7));
                        icbcTran.setIncomeExpenseAmt(cols.get(8));
                        icbcTran.setBalance(cols.get(9));
                        icbcTran.setChannel(cols.get(11));
                        icbcTran.setConterpartyAccountNo(counterpartyAcc);
                        icbcTran.setCounterpartyName(counterpartyName);
                        icbcTrans.add(icbcTran);
                    }
                }
            } else {
                List<String> cols = Splitter.on(StringUtils.SPACE).splitToList(row.trim());
                if (cols.size() == 12) {
                    icbcTran.setTranDate(cols.get(0).concat(cols.get(1)));
                    icbcTran.setAccountNo(cols.get(2));
                    icbcTran.setAccountType(cols.get(3));
                    icbcTran.setSequenceNo(cols.get(4));
                    icbcTran.setCurrency(cols.get(5));
                    icbcTran.setCashExchange(cols.get(6));
                    icbcTran.setComment(cols.get(7));
                    icbcTran.setZone(cols.get(8));
                    icbcTran.setIncomeExpenseAmt(cols.get(9));
                    icbcTran.setBalance(cols.get(10));
                    icbcTran.setChannel(cols.get(11));
                    icbcTrans.add(icbcTran);
                }
                // 有对方户名 & 对方账号
                else if (cols.size() == 14) {
                    icbcTran.setTranDate(cols.get(0).concat(cols.get(1)));
                    icbcTran.setAccountNo(cols.get(2));
                    icbcTran.setAccountType(cols.get(3));
                    icbcTran.setSequenceNo(cols.get(4));
                    icbcTran.setCurrency(cols.get(5));
                    icbcTran.setCashExchange(cols.get(6));
                    icbcTran.setComment(cols.get(7));
                    icbcTran.setZone(cols.get(8));
                    icbcTran.setIncomeExpenseAmt(cols.get(9));
                    icbcTran.setBalance(cols.get(10));
                    icbcTran.setCounterpartyName(cols.get(11));
                    icbcTran.setConterpartyAccountNo(cols.get(12));
                    icbcTran.setChannel(cols.get(13));
                    icbcTrans.add(icbcTran);
                }
            }
        }

        return icbcTrans;
    }

    private void parseBalanceAndCounterpartyNameAndCounterpartyAccountNo(String text, ICBCTran icbcTran) {
        // 525.10工银信使(个人)收入@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@23094424115008797
        Pattern pattern = Pattern.compile("(([0-9]{1,3}(,[0-9]{3})*)(\\.[0-9]{2}))");
        Matcher matcher = pattern.matcher(text);
        if (matcher.find()) {
            icbcTran.setBalance(matcher.group());
            String lastTwoColumn = text.substring(matcher.end());
            pattern = Pattern.compile("[0-9]{9,19}$");
            matcher = pattern.matcher(lastTwoColumn);
            if (matcher.find()) {
                icbcTran.setCounterpartyName(lastTwoColumn.substring(0, matcher.start()));
                icbcTran.setConterpartyAccountNo(matcher.group());
            }
        }
    }

    @Override
    public String parsePdfHeaderText(String filePath, String pdfPassword) {
        String pdfHeaderText = "";
        try (PDDocument pdDocument = PDDocument.load(new File(filePath), pdfPassword)) {
            PDFTextStripper stripper = new PDFTextStripper();
            stripper.setSortByPosition(false);
            stripper.setStartPage(1);
            stripper.setEndPage(1);
            pdfHeaderText = stripper.getText(pdDocument);
            pdfHeaderText = pdfHeaderText.replace(System.getProperty("line.separator", "\n"), "");
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), "", "", "", "parsePdfHeaderText failed", e);
            throw new RuntimeException(e);
        }
        return pdfHeaderText;
    }

	public static void main(String[] args) {
		ICBCPdfParser icbcPdfParser = new ICBCPdfParser();
		ICBC icbc;
		String json;
		icbc = icbcPdfParser.parseICBCPdf("D:\\data\\files\\ICBC\\工商银行历史明细（密码773474）.pdf", "773474");
		json = JsonUtils.convertObjectToJson(icbc);
		log.info(json);
		icbc = icbcPdfParser.parseICBCPdf("D:\\data\\files\\ICBC\\zd4g3dtt1545020203300188160_080b13a3aacebdf83e4064f3fca22c13_beehive-icbc_jyls-0-244476.pdf", "244476");
		json = JsonUtils.convertObjectToJson(icbc);
		log.info(json);
		icbc = icbcPdfParser.parseICBCPdf("D:\\data\\files\\ICBC\\zd4g3dtt1547451939254595584_d98c375d520d1188005e856fd16c1c7a_beehive-icbc_jyls-0-080070.pdf", "080070");
		json = JsonUtils.convertObjectToJson(icbc);
		log.info(json);
		icbc = icbcPdfParser.parseICBCPdf("D:\\data\\files\\ICBC\\111-223722.pdf", "223722");
		json = JsonUtils.convertObjectToJson(icbc);
		log.info(json);
		icbc = icbcPdfParser.parseICBCPdf("D:\\data\\files\\ICBC\\zd2fx6t01610577328730259456_f61473508bc0b2e4126370ea06036bd2_beehive-icbc_jyls-0-542322.pdf", "542322");
		json = JsonUtils.convertObjectToJson(icbc);
		log.info(json);
		icbc = icbcPdfParser.parseICBCPdf("D:\\data\\files\\ICBC\\zd4q0c2v1758407655625093120_f2162068daa3259ab3564bd39596b7fe_beehive-icbc_jyls-0-115482.pdf", "115482");
		json = JsonUtils.convertObjectToJson(icbc);
		log.info(json);
		System.out.println(json);
        icbc = icbcPdfParser.parseICBCPdf("D:\\zd4zxas41778597468941197312_ed94786949015083d7311518682504af_beehive-icbc_jyls-0.pdf", "758876");
        json = JsonUtils.convertObjectToJson(icbc);
        log.info(json);
        System.out.println(json);
	}

}
